﻿using System;
using System.IO;
using AutoBuild.Core;
using AutoBuild.Core.Configuration;
using AutoBuild.Core.Framework;
using Machine.Specifications;
using Rhino.Mocks;

namespace AutoBuild.Specs.Core
{
    [Subject(typeof(AutoBuildRunner))]
    public class when_executing : AutoBuildRunnerSpecs
    {
        Because of = () =>
            Subject.Start(autoBuildArguments);

        It should_start_watching_directory = () =>
            directoryWatcher.WasCalled(w => w.Watch( Path.Combine(Environment.CurrentDirectory, ".")));
    }

    
    [Subject(typeof(AutoBuildRunner))]
    public class when_a_file_has_changed : AutoBuildRunnerSpecs
    {
        Because of = () =>
        {
            Subject.Start(autoBuildArguments);
            directoryWatcher.Raise(w => w.FileChanged += null, null,
                                   new FileSystemEventArgs(WatcherChangeTypes.Changed, string.Empty, fileName));
        };

        It should_disable_file_watcher = () =>
            directoryWatcher.WasCalled(w => w.Disable());

        It should_send_file_changed_debug_message_to_console = () =>
            console.WasCalled(l => l.Debug(Arg<string>.Is.NotNull));


        It should_run_the_build = () =>
            buildRunner.WasCalled(b => b.RunBuild(autoBuildArguments));
    }

    [Subject(typeof(AutoBuildRunner))]
    public class when_the_build_completes : AutoBuildRunnerSpecs
    {
        Because of = () =>
        {
            Subject.Start(autoBuildArguments);
            buildRunner.Raise(b => b.BuildCompleted += null, null, EventArgs.Empty);
        };

        It should_enable_file_watcher = () =>
            directoryWatcher.WasCalled(w => w.Enable());
    }

    public abstract class AutoBuildRunnerSpecs : Specification<AutoBuildRunner>
    {
        protected static AutoBuildArguments autoBuildArguments;
        protected static IDirectoryWatcher directoryWatcher;
        protected static IBuildRunner buildRunner;
        protected static IRunnerSelector runnerSelector;
        protected static IConsole console;
        protected static string fileName;


        Establish context = () =>
        {
            fileName = Path.GetTempFileName();
            autoBuildArguments = new AutoBuildArguments
                {
                    BuildFile = fileName,
                    RunnerName = "NAnt",
                    WatchFolder = "."
                };
            directoryWatcher = Mock<IDirectoryWatcher>();
            console = Mock<IConsole>();

            buildRunner = Mock<IBuildRunner>();
            buildRunner.Expect(x => x.RunnerName).Return("NAnt");

            runnerSelector = Mock<IRunnerSelector>();
            runnerSelector.Expect(r => r.GetAvailableRunners()).Return(new[] {buildRunner});
            runnerSelector.Expect(r => r.GetRunner("NAnt")).Return(buildRunner);

            Subject = new AutoBuildRunner(
                directoryWatcher, 
                runnerSelector, 
                console
                );
        };

        Cleanup in_the_end = () =>
        {
            try
            {
                File.Delete(fileName);
            }
            catch (Exception)
            {
            }
        };
    }
}